/*
 * program.cpp
 *
 *  Created on: 29.01.2012
 *      Author: ignacio
 */

#include "program.h"
#include "CL_Character.h"
#include "kinematic.h"
#include "steering.h"
#include "flock.h"
#include "path.h"
#include "Gluon.h"
#include "Astar.h"
#include "cartography.h"


typedef neurignacio::Vector3 Vector;
typedef neurignacio::angle Angle;
using neurignacio::CL_Character;
using neurignacio::real;

#include "timing.h"

#include <iostream>
using std::cout;
using std::endl;
#include <sstream>
//#include <algorithm>
//using std::sort;
//#include <cstring>

// #define M_PI 3.14159265358979323846f // M_PI is defined in math.h
//WINDOW
#define NUM_OF_FRAMES 10000
#define JPEG_OUPUT false
#define VERBOSITY false//true
#define WINDOWSIZE_X 512
#define WINDOWSIZE_Y 512
#define WORLD_SIZE_X 100
#define WORLD_SIZE_Y 100
#define WORLD_CENTER Vector(0.0f,0.0f)
#define WINDOW_CENTER Vector(WINDOWSIZE_X/2, WINDOWSIZE_Y/2)
#define UL_WINDOWCORNER Vector(0,0)
#define UR_WINDOWCORNER Vector(0, WINDOWSIZE_Y-1)
#define LL_WINDOWCORNER Vector(WINDOWSIZE_X-1, 0)
#define LR_WINDOWCORNER Vector(WINDOWSIZE_X-1, WINDOWSIZE_Y-1)
#define SPRITE_SIZE_X 20/2
#define SPRITE_SIZE_Y 50/2
#define BACKGROUND_COLOR CL_Colorf(0.0f,0.0f,0.0f, 0.0f)
//CHARACTER
#define CHARACTER_COLOR CL_Color::yellow
#define CHARACTER_POSITION_X 0.0f
#define CHARACTER_POSITION_Y 0.0f
#define CHARACTER_POSITION_Z -WORLD_SIZE_Y
#define CHARACTER_ORIENTATION Angle(90.f, degrees) // =radians => 120°
#define CHARACTER_MINVELOCITY 0.1f
#define CHARACTER_INITIALVELOCITY Vector(0,0,0);
#define CHARACTER_MAXSPEED 10.0f
#define CHARACTER_MAXROTATION Angle(20, cl_degrees) // angular velocity (degrees/time)
#define CHARACTER_MAXACCELERATION 20.0f	// linear acceleration
#define CHARACTER_MAXANGULARACCELERATION Angle(300, cl_degrees) // angular acceleration (degrees/time²)
#define CHARACTER_VOLATILITY 10.0f // Default=20.0f
#define CHARACTER_TURNSPEED 20.0f
//TARGET
#define TARGET_COLOR CL_Color::red
#define TARGET_POSITION_X -20.0f
#define TARGET_POSITION_Y 0.0f
#define TARGET_POSITION_Z -20.0f
#define TARGET_ORIENTATION Angle(30, degrees)	// =radians => ~45°
#define TARGET_MINVELOCITY 0.1f
#define TARGET_INITIALVELOCITY Vector(0,0,0)
#define TARGET_MAXSPEED 10.0f	// Default=7.0f
#define TARGET_MAXROTATION Angle(90, cl_degrees) // angular velocity (degrees/time)
#define TARGET_MAXACCELERATION 20.0f	// linear acceleration (Default=20.0f)
#define TARGET_MAXANGULARACCELERATION Angle(300, cl_degrees) // angular acceleration (degrees/time²)
#define TARGET_VOLATILITY 20.0f
#define TARGET_TURNSPEED 20.0f
// KINEMATIC
#define REFRESH_TIME 1
#define TIME_TO_TARGET 0.1f
#define ARRIVE_RADIUS 1.0f
// STEERING
#define TARGET_RADIUS 5.f // linear distance for arriving at the target
#define TARGET_RADIUS_ROTATION Angle(5, cl_degrees) // angular distance for arriving at the target
#define SLOW_RADIUS 20.0f	// linear distance for beginning to slow down
#define SLOW_RADIUS_ROTATION Angle(15, cl_degrees) // angular distance for arriving at the target
#define TIME_TO_TARGET_ROTATION 0.1f

#define PURSUE_MAXPREDICTION 10.0f // Default 10.0f

#define FLEE true
#define MAX_PREDICTION_TIME 0.1f
#define WANDER_OFFSET 20
#define WANDER_RADIUS 100
#define WANDER_RATE Angle(90, cl_degrees)

#define THRESHOLD_DISTANCE 1
#define DECAY_COEFFICIENT 1
#define COLLISION_RADIUS 7

#define HOUSE_SIZE 10

//#include <ctime>

void Program::run(void)
{
//	neurignacio::cartography_example();
//	CL_PixelBuffer png_rgba8(242,242,cl_rgba8);
	CL_PixelBuffer png_copy = CL_PNGProvider::load("./Resources/maze_5055001m.png");
//	png_copy.convert(png_rgba8);
	CL_PixelBuffer png_image(png_copy.get_width(), png_copy.get_height(), cl_rgba8);	// somehow get_pixel works only with CL_TextureFormat=cl_rgba8
	png_copy.convert(png_image);
//	CL_PixelBuffer png_image(png_rgba8);
	CL_PNGProvider::save(png_image, "./Resources/maze_difficult_invert_copy.png");
	cout << "Is Null: " << png_image.is_null() << endl;
	cout << "Width: " << png_image.get_width() << " Height: " << png_image.get_height() << endl;
	cout << "Pitch: " << png_image.get_pitch() << endl;
	cout << "Color Key? " << png_image.has_colorkey() << " Color Key: " << png_image.get_colorkey() << endl;
	cout << "Bytes per Pixel: " << png_image.get_bytes_per_pixel() << endl;
	cout << "Red Mask: " << png_image.get_red_mask() << endl;
	cout << "Green Mask: " << png_image.get_green_mask() << endl;
	cout << "Blue Mask: " << png_image.get_blue_mask() << endl;
	cout << "Alpha Mask: " << png_image.get_alpha_mask() << endl;
	cout << "Texture Format: " << png_image.get_format() << endl;

	neurignacio::BinaryMask mask(png_image);
	CL_Colorf pixel=png_copy.get_pixel(4,4);
	cout << "IMAGE(4,4): " << pixel.get_red() << "," << pixel.get_green() << "," << pixel.get_blue() << "," << pixel.get_alpha() << endl;
	cout << "Making Binary" << endl;
	mask.binarize(255,255,0);
	CL_PixelBuffer png_copy1=mask.getBuffer();
	CL_PNGProvider::save(png_copy1, "./Resources/maze_difficult_binary_01.png");
	cout << "Skeletonize" << endl;
	mask.skeletonize_ij(255);
	CL_PixelBuffer png_copy2=mask.getBuffer();
	CL_PNGProvider::save(png_copy2, "./Resources/maze_difficult_skeleton_01.png");
	cout << "Searching Intersections" << endl;
	neurignacio::BinaryMask::VectorList intersections=mask.intersections(255);
	cout << "Finding Connections" << endl;
	neurignacio::Hypergraph<neurignacio::Vector3> G=mask.connections(intersections,255);
	cout << "Graph Connections: size=" << G.size() << endl;

	cout << G;
	neurignacio::Vector3 startPoint(363,395);
	neurignacio::Vector3 endPoint(396, 36);
	cout << "A_Star:"<< endl;
	G.A_Star(startPoint,endPoint);
	G.PrintPath(startPoint,endPoint);
	// Export Path to Clanlib
	neurignacio::Path<neurignacio::VectorVertex> vertexPath=G.getPath(startPoint,endPoint);
	neurignacio::VectorPath vectorPath=neurignacio::VertexPathToVectorPath(vertexPath);
	cout << "DONE." << endl;

	CL_Sprite maze(gc,"./Resources/maze_5055001m.png");
	neurignacio::CL_Path cl_path(gc, vectorPath, gc.get_width(), gc.get_height(), CL_Colorf::red);
	cout << "SIZE OF CL_PATH: " << cl_path.size() << endl;
	cout << cl_path << endl;
	gc.clear(CL_Colorf::white);
	gc.set_blend_mode(blend_transparent);
	maze.draw(gc,0,0);
	cl_path.draw();
	std::stringstream filename2;
	filename2 <<"maze_solution2.png";
	CL_PNGProvider::save(gc.get_pixeldata(), filename2.str());

return;
	std::stringstream out;
	quit = false;

	CL_Colorf backgroundColor = BACKGROUND_COLOR;
	CL_Colorf noiseColor(CL_Color::darkslategrey);
//	unsigned int time_last = CL_System::get_time(); // **********  <= TIME LAST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


	// Initialize Characters Dummies
	Vector spriteSize;
	spriteSize.x=SPRITE_SIZE_X;
	spriteSize.y=SPRITE_SIZE_Y;
//	out << spriteSize << endl;
	// Character Dummy
	// Load Character Template
	CL_Character character(gc, "./Resources/white_triangle.png", WORLD_SIZE_X, WORLD_SIZE_Y);
	// Assign Color
	character.set_color(CHARACTER_COLOR);
//	Modify Scale
	character.set_scale(static_cast<float>(spriteSize.x)/character.get_width(), static_cast<float>(spriteSize.y)/character.get_height());
//	Character Properties
	character.position.x=CHARACTER_POSITION_X;
	character.position.y=CHARACTER_POSITION_Y;
	character.position.z=CHARACTER_POSITION_Z;
	character.orientation=CHARACTER_ORIENTATION;
	character.minVelocity=CHARACTER_MINVELOCITY;
    character.velocity=CHARACTER_INITIALVELOCITY;
	character.maxSpeed=CHARACTER_MAXSPEED;
	character.maxRotation=CHARACTER_MAXROTATION;
	character.maxAcceleration=CHARACTER_MAXACCELERATION;
	character.maxAngularAcceleration=CHARACTER_MAXANGULARACCELERATION;
	character.setEpsilonParameters();


	// Target Dummy
	CL_Character target(gc, "./Resources/white_triangle.png", WORLD_SIZE_X, WORLD_SIZE_Y);
	target.set_scale(static_cast<float>(spriteSize.x)/target.get_height(), static_cast<float>(spriteSize.y)/target.get_width());
	target.set_color(TARGET_COLOR);
	target.position.x=TARGET_POSITION_X;
	target.position.y=TARGET_POSITION_Y;
	target.position.z=TARGET_POSITION_Z;
	target.orientation=TARGET_ORIENTATION;
	target.minVelocity=TARGET_MINVELOCITY;
    target.velocity=TARGET_INITIALVELOCITY;
	target.maxSpeed=TARGET_MAXSPEED;
	target.maxRotation=TARGET_MAXROTATION;
	target.maxAcceleration=TARGET_MAXACCELERATION;
	target.maxAngularAcceleration=TARGET_MAXANGULARACCELERATION;
	target.setEpsilonParameters();

	// Path Dummy
	Vector A(-10,0,-10);
	Vector B(50,0,-50);
	Vector C(10,0,10);
	Vector D(-50,0,50);
	neurignacio::CL_Path path(gc, WORLD_SIZE_X, WORLD_SIZE_Y, CL_Colorf::white);
	path.push_back(character.position);
	path.push_back(A);
	path.push_back(B);
	path.push_back(C);
	path.push_back(D);
	cout << path << endl;
	Vector Z(50,0,51);
	Vector point;

	real parameter=path.getParameterClosestToPoint(Z);
	point=path.closestToPoint(Z);
	cout << Z << " parameter: " << parameter << " => "  << path.getPointFromParameter(parameter) << endl;



/*
    // Holds the KINEMATIC behaviours. //
    neurignacio::KinematicSeek *seek;
    neurignacio::KinematicFlee *flee;
    neurignacio::KinematicArrive *arrive;
    neurignacio::KinematicWander *wander;
    const char **status;
    // Set up all possible behaviours
    seek = new neurignacio::KinematicSeek[2];
    flee = new neurignacio::KinematicFlee[2];
    arrive = new neurignacio::KinematicArrive[2];
    wander = new neurignacio::KinematicWander[2];
*/
//	Create Behaviours
    neurignacio::Seek *seek;
    neurignacio::Flee *flee;
    neurignacio::Arrive *arrive;
    neurignacio::Wander *wander;
    neurignacio::Align *align;
    neurignacio::Idle *idle;
    neurignacio::VelocityMatch *velocityMatch;
    neurignacio::Pursue *pursue;
    neurignacio::Evade *evade;
    neurignacio::Face *face;
    neurignacio::LookWhereYoureGoing *look;
    neurignacio::Separation *separation;
    neurignacio::Attraction* attraction;
    neurignacio::CollisionAvoidance* collision;


    // Set up all possible behaviours
    seek = new neurignacio::Seek[2];
    flee = new neurignacio::Flee[2];
    arrive = new neurignacio::Arrive[2];
    wander = new neurignacio::Wander[2];
    align = new neurignacio::Align[2];
    velocityMatch=new neurignacio::VelocityMatch[2];
    idle = new neurignacio::Idle[2];
    pursue = new neurignacio::Pursue[2];
    evade = new neurignacio::Evade[2];
    face=new neurignacio::Face[2];
    look=new neurignacio::LookWhereYoureGoing[2];
    separation = new neurignacio::Separation[2];
    attraction = new neurignacio::Attraction[2];
    collision = new neurignacio::CollisionAvoidance[2];

    seek[0].setTarget(&target); // Character seeks Target
    seek[1].setTarget(&character); // Target seeks Character

    flee[0].setTarget(&target); // Character flees Target
    flee[1].setTarget(&character); // Target flees Character

    align[0].setTarget(&target); // Character aligns Target
    align[1].setTarget(&character); // Target aligns Character

    face[0].setTarget(&target); // Character faces Target
    face[1].setTarget(&character); // Target faces Character

    velocityMatch[0].setTarget(&target); // Character matches Target
    velocityMatch[1].setTarget(&character); // Target matches Character

    pursue[0].setTarget(&target); // Character matches Target
    pursue[1].setTarget(&character); // Target matches Character

    evade[0].setTarget(&target); // Character evades Target
    evade[1].setTarget(&character); // Target evades Character

    separation[0].setTarget(&target);
    separation[1].setTarget(&character);

    attraction[0].setTarget(&target);
    attraction[1].setTarget(&character);

    collision[0].setTarget(&target);
    collision[1].setTarget(&character);
//	Follow Path
    neurignacio::SeekPath followPath;
    followPath.TargetPath::setTarget(&path);
    followPath.maxPrediction=MAX_PREDICTION_TIME;
    followPath.pathOffset = 0.1;


// Only in KINEMATIC
    neurignacio::Vector3 destinationPoint1(-20,0,20);
    arrive[0].setTarget(&destinationPoint1); // Character arrives Target
    neurignacio::Vector3 destinationPoint2(20,0,20);
    arrive[1].setTarget(&destinationPoint1); // Target arrives Character

    for (unsigned char i = 0; i<2; ++i)
    {
    	arrive[i].targetRadius=TARGET_RADIUS;
    	arrive[i].slowRadius=SLOW_RADIUS;
    	arrive[i].timeToTarget=TIME_TO_TARGET;
    	arrive[i].priority=0;

    	align[i].targetAngularDistance=TARGET_RADIUS_ROTATION;
    	align[i].slowAngularDistance=SLOW_RADIUS_ROTATION;
    	align[i].timeToTarget=TIME_TO_TARGET_ROTATION;

    	face[i].targetAngularDistance=TARGET_RADIUS_ROTATION;
    	face[i].slowAngularDistance=SLOW_RADIUS_ROTATION;
    	face[i].timeToTarget=TIME_TO_TARGET_ROTATION;

    	look[i].targetAngularDistance=TARGET_RADIUS_ROTATION;
    	look[i].slowAngularDistance=SLOW_RADIUS_ROTATION;
    	look[i].timeToTarget=TIME_TO_TARGET_ROTATION;
    	look[i].priority=5;

    	velocityMatch[i].timeToTarget=TIME_TO_TARGET;

    	pursue[i].maxPrediction=PURSUE_MAXPREDICTION;
    	evade[i].maxPrediction=PURSUE_MAXPREDICTION;

        wander[i].wanderOffset=10;
        wander[i].wanderRadius=5;
        wander[i].wanderRate=50;
        wander[i].timeToTarget=TIME_TO_TARGET_ROTATION;

        separation[i].thresholdDistance = THRESHOLD_DISTANCE;
        separation[i].decayCoefficient = DECAY_COEFFICIENT;

        attraction[i].thresholdDistance = THRESHOLD_DISTANCE;
        attraction[i].decayCoefficient = DECAY_COEFFICIENT;

        collision[i].collisionRadius = COLLISION_RADIUS;
        collision[i].maxPrediction = PURSUE_MAXPREDICTION;
        collision[i].priority=5;
    }



    // Set the initial behaviours
    // character will be the parent, so behaviour is added after defining flock
    character.addMovementBehaviour(&followPath);
    out << "CHARACTER MOVEMENT BEHAVIOUR: " << character.whichMovementBehaviour();
    out << " Description: "<< character.movementBehaviour[0]->MovementBehaviour_ID_Description() << endl;
	out << "\tCharacter Position: " << character.position << " Orientation: " << character.orientation << endl;

	target.addMovementBehaviour(&idle[1]);
    out << "TARGET MOVEMENT BEHAVIOUR: " << target.whichMovementBehaviour();
    out << " Description: "<< target.movementBehaviour[0]->MovementBehaviour_ID_Description() << endl;
    out << "\tTarget Position: " << target.position << " Orientation: " << target.orientation << endl;

    out << "HERE!!! LINE: " << __LINE__ << endl;

	// Create movement behaviour for Flock
	neurignacio::MovementBehaviourPointerContainer flockMovementBehaviourContainer;

	// Create Flock
	neurignacio::Flock flock;
//	flock.horizont=10;
//	flock.fieldOfView=Angle(90);

	// Populate House
	neurignacio::House<neurignacio::CL_Character> house;
	house.push_back(character);	// house[0]=character;
	for (int i=0; i<HOUSE_SIZE; ++i)	// house[1..10]=target
	{
		house.push_back(target);
		house.back()->position.random(neurignacio::TimingData::getTime()*i);
		house.back()->position.x *= 10;
		house.back()->position.y = 0;
		house.back()->position.z *= 10;
	}

	// Create Parent that will carry the flock behaviour
	// In this example, character (i.e. house[0]) is the parent
	neurignacio::CL_Character* parent=&house[0];//(gc, "./Resources/white_triangle.png", WORLD_SIZE_X, WORLD_SIZE_Y);
	parent->addMovementBehaviour(&flock);

	// Create TargetLeptonPointerContainer for Flock
	neurignacio::CL_CharacterPointerContainer characterPointerContainer;
	out << "Address of character: " << &character << " Parent: " << parent << endl;
	for (neurignacio::House<neurignacio::CL_Character>::iterator character=house.begin(); character!=house.end(); ++character)
	{
		out << "Address of " << (*character)->position << ": " << character->get() << endl;
		if (character->get()!=parent) // In this example I want to include the whole house but not the parent in the target Container
		{

			neurignacio::CL_Character* lepton=&(**character);
			characterPointerContainer.push_back(lepton);
			out << "\tcharacterPointerContainer.size(): " << characterPointerContainer.size() << endl;
		}
	}

	out << "Size of characterPointerContainer: " << characterPointerContainer.size() << endl;
	for (neurignacio::CL_CharacterPointerContainer::iterator boid=characterPointerContainer.begin(); boid!=characterPointerContainer.end(); ++boid)
		out << "\tcharacterPointerContainer: " << (*boid)->position << endl;

	// Setup Flock
	flock.characterContainer.copy(characterPointerContainer);
//	flock.targetContainer.copy(characterPointerContainer);
//	flock.movementBehaviour=&flockMovementBehaviourContainer;
	flock.arrive.setTarget(parent);
	flock.arrive.targetRadius=TARGET_RADIUS;
	flock.arrive.slowRadius=SLOW_RADIUS;
	flock.arrive.timeToTarget=TIME_TO_TARGET;
	flock.arrive.priority=0;
	flock.arrive.weight=1;
	flock.look.targetAngularDistance=TARGET_RADIUS_ROTATION;
	flock.look.slowAngularDistance=SLOW_RADIUS_ROTATION;
	flock.look.timeToTarget=TIME_TO_TARGET_ROTATION;
	flock.look.priority=1;
	flock.look.weight=1;
	flock.collision.collisionRadius = COLLISION_RADIUS;
	flock.collision.maxPrediction = MAX_PREDICTION_TIME;
	flock.collision.priority=1;
	flock.collision.weight=1;


	// Asign the behaviours dependent on flock
//    flockMovementBehaviourContainer.push_back(&collision[0]);
//    flockMovementBehaviourContainer.push_back(&arrive[0]);
//    flockMovementBehaviourContainer.push_back(&look[0]);

	// Parenting
	neurignacio::CL_CharacterParent mother;
	mother.parent=parent;
	mother.children=&characterPointerContainer;
	mother.parentVisibility=true;

	float scaleX, scaleY;
	character.get_scale(scaleX, scaleY);
	unsigned long int frame = 0;
	unsigned startTime=neurignacio::TimingData::getTime();
	while (!quit)
	{
		// Check for EXIT KEY
		if(keyboard.get_keycode(CL_KEY_ESCAPE))
		{
			quit = true;
			break;
		}

		// Update Characters
		if (frame<NUM_OF_FRAMES)
		{
			// Update the timing.
			neurignacio::TimingData::get().update();

			// Clean Screen
			gc.clear(BACKGROUND_COLOR);
			gc.set_blend_mode(blend_transparent);
			mother.getSteering();
			out << "program.cpp - REFRESH!!!!!!!!!!!!!!!!" << endl;
			mother.refresh();
			mother.bringBackToWorld();
			mother.draw();
			path.draw();

/*
			out << frame << "#" << "(" << (neurignacio::TimingData::getTime()-startTime)*0.001 << " s)" << endl;
			out << "\t################# CHARACTER STEERING " << character.position << " ################" << endl;
			character.getSteering();
			out << "\tooooooooooooooooo TARGET STEERING " << target.position << " oooooooooooooooooo" << endl;
			target.getSteering();
			out << "\t................. CHARACTER REFRESH ................" << endl;
			character.refresh();
			out << "\t----------------- TARGET REFRESH ------------------" << endl;
			target.refresh();
			if (!character.isInsideWorld())
				character.position=WORLD_CENTER;
			if (!target.isInsideWorld())
				target.position=WORLD_CENTER;

		// Draw Characters
		character.draw(VERBOSITY);
		target.draw(VERBOSITY);
*/
/*			flock.getSteering();
			// Draw Flock
			for (neurignacio::GluonContainer::iterator boid=group.begin();boid!=group.end(); ++boid)
			{
				CL_Character CL_boid = *(*boid);
				out << "Drawing " << CL_boid << endl;
			}

*/
			++frame;
		} // end if frame>NUM_OF_FRAMES

		// Flip Screen
		window.flip();
		if (JPEG_OUPUT)
		{
			std::stringstream filename;
			filename <<"prueba" << frame << ".jpg";
			if (frame<NUM_OF_FRAMES) CL_JPEGProvider::save(gc.get_pixeldata(), filename.str());
		}
		CL_KeepAlive::process();
		CL_System::sleep(REFRESH_TIME);
	}
	cout << "Running Time: " << frame << " frames in " << (neurignacio::TimingData::getTime()-startTime)*0.001f << " sec (" << frame*1000.0f/(neurignacio::TimingData::getTime()-startTime) << " fps)" << endl;

	delete [] seek;
	delete [] flee;
	delete [] arrive;
	delete [] wander;
    delete [] align;
    delete [] velocityMatch;
    delete [] idle;
    delete [] pursue;
    delete [] evade;
    delete [] face;
    delete [] look;
    delete [] separation;
    delete [] attraction;
}

void Program::init(void)
{
	neurignacio::TimingData::init();
}

void Program::deinit(void)
{
	neurignacio::TimingData::deinit();
}

int init::main(const std::vector<CL_String> &args)
{
	CL_SetupCore setup_core;
	CL_SetupDisplay setup_display;
	CL_SetupGL1 setup_gl;  // My macbook uses only openGL 1.3 :-(
//		CL_SetupSWRender setup_swrender;

	try
		{
			Program program("SmartCones",WINDOWSIZE_X, WINDOWSIZE_Y);
			program.init();
			program.run();
			program.deinit();
		}
	catch(CL_Exception &exception)
		{
			// Create a console window for text-output if not available
			CL_ConsoleWindow console("Console", 80, 160);
			CL_Console::write_line("Error: " + exception.get_message_and_stack_trace());
			console.display_close_message();

			return -1;
		}

	return 0;
}

Program::Program(char* windowTitle, int width, int height)
: window_desc(windowTitle, CL_Size(width, height), true),
  window(window_desc),
  slot_quit(window.sig_window_close().connect(this, &Program::on_window_close)),
  gc(window.get_gc()),
  keyboard(window.get_ic().get_keyboard())
{
	//
	blend_transparent.enable_blending(true);
}


